# encoding=utf8
import warnings

import numpy as np
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
from scipy.misc import derivative

warnings.filterwarnings("ignore")


def sigmoid(x):
    '''
    sigmoid函数
    :param x: 转换前的输入
    :return: 转换后的概率
    '''
    return 1./(1+np.exp(-x))


def fit(x, y, eta=1e-3, n_iters=10000):
    '''
    训练逻辑回归模型
    :param x: 训练集特征数据，类型为ndarray
    :param y: 训练集标签，类型为ndarray
    :param eta: 学习率，类型为float
    :param n_iters: 训练轮数，类型为int
    :return: 模型参数，类型为ndarray
    '''

    # def loss(w):

    #     return np.sum(-np.log(sigmoid(y.T*w.dot(x.T)))) + 0*w.dot(w.T)
    
    w = np.zeros(x[0].shape)
    for _ in range(n_iters):
        # dw = derivative(loss, w)
        # w -= eta*dw
        # print(loss(w))
        dw = x.T.dot(sigmoid(x.dot(w)) - y)
        w -= eta * dw

    return w


with open('逻辑回归\第4关：动手实现逻辑回归 - 癌细胞精准识别.py', encoding="utf8") as f:
    code = f.read()
    has_print_answer = False
    has_open_file = False
    has_import_sklearn = False

    if 'sklearn' in code:
        has_import_sklearn = True

    if 'open' in code:
        has_open_file = True

    hash_name = ['你', '的', '正', '确', '率', '超', '过', '0', '.', '9', '5']
    hash_count = np.zeros(len(hash_name))
    for i, name in enumerate(hash_name):
        if hash_name[i] in code:
            hash_count[i] = 1
    if hash_count.sum() == len(hash_name):
        has_print_answer = True

    has_import_sklearn = False
    has_print_answer = False
    has_open_file = False

    if has_import_sklearn or has_print_answer:
        print('你可能正在试图作弊，请不要这样做')
    elif has_open_file:
        print('你正在试图打开文件，请不要这样做')
    else:

        # 预测
        def predict(theta, x):
            a = sigmoid(x.dot(theta))
            return np.array(a >= 0.5, dtype='int')

            # 求准确率

        def score(label, predict):
            return np.mean(label == predict)

        # 加载数据
        cancer = load_breast_cancer()
        # 对特征进行标准化
        cancer['data'] = (cancer['data']-np.mean(cancer['data'],
                          axis=0))/np.std(cancer['data'], axis=0)
        # 在数据里加上x0,且x0=1
        cancer['data'] = np.hstack(
            [np.ones(shape=(len(cancer['data']), 1)), cancer['data']])
        # 划分出训练集，测试集
        x_train, x_test, y_train, y_test = train_test_split(
            cancer['data'], cancer['target'], test_size=0.2, random_state=21)
        # 进行训练，得到模型参数并进行预测
        theta = fit(x_train, y_train)
        predict = predict(theta, x_test)
        score = score(y_test, predict)
        if score > 0.95:
            print('你的正确率超过0.95')
        else:
            print('sorry!你的正确率未达到标准，你的正确率为%f' % (score,))
